/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package net.octopeer.message;

import java.io.File;
import java.io.StringReader;

import java.util.ArrayList;

import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;

import org.xml.sax.InputSource;

import net.octopeer.core.PeerNode;
import net.octopeer.utilities.XMLTools;
import net.octopeer.utilities.SimpleSHA1;

/**
 *
 * @author andria
 */
public class Request {
    private String reqID;
    private String reqType;
    private String reqKeyword;
    private PeerNode reqPeer;
    private int reqTtl;
    private ArrayList<PeerNode> pathPeers;
    
    public Request() {
        this.pathPeers = new ArrayList<PeerNode>();
    }
    
    public Request(String reqType, String reqKeyword, PeerNode reqPeer, int reqTtl, 
            ArrayList<PeerNode> pathPeers) throws Exception {
        this.reqID = SimpleSHA1.SHA1(reqType + reqKeyword + reqPeer.getNodeID());
        this.reqType = reqType;
        this.reqKeyword = reqKeyword;
        this.reqPeer = reqPeer;
        this.reqTtl = reqTtl;
        this.pathPeers = pathPeers;
    }
    
    public Request(String reqType, String reqKeyword, PeerNode reqPeer, int reqTtl, 
            PeerNode pathPeer) throws Exception {
        this.reqID = SimpleSHA1.SHA1(reqType + reqKeyword + reqPeer.getNodeID());
        this.reqType = reqType;
        this.reqKeyword = reqKeyword;
        this.reqPeer = reqPeer;
        this.reqTtl = reqTtl;
        this.pathPeers = new ArrayList<PeerNode>();
        this.pathPeers.add(pathPeer);
    }
    
    public Request(Request oldReq) {
        this.reqID = oldReq.getReqID();
        this.reqType = oldReq.getReqType();
        this.reqKeyword = oldReq.getReqType();
        this.reqPeer = oldReq.getReqPeer();
        this.reqTtl = oldReq.getReqTtl();
        this.pathPeers = oldReq.getPathPeers();
    }
    
    public void setReqID(String reqID) {
        this.reqID = reqID;
    }
    
    public void setReqType(String reqType) {
        this.reqType = reqType;
    }
    
    public void setReqKeyword(String reqKeyword) {
        this.reqKeyword = reqKeyword;
    }
    
    public void setReqPeer(PeerNode reqPeer) {
        this.reqPeer = reqPeer;
    }
    
    public void setReqTtl(int reqTtl) {
        this.reqTtl = reqTtl;
    }
    
    public void decReqTtl() {
        this.reqTtl = this.reqTtl - 1;
    }
    
    public void setReqPathPeers(ArrayList<PeerNode> reqPathPeers) {
        this.pathPeers = reqPathPeers;
    }
    
    public void addPathPeer(PeerNode peer) {
        this.pathPeers.add(peer);
    }
    
    public PeerNode remPathPeer() {
        PeerNode result = null;
        
        result = this.pathPeers.remove(this.pathPeers.size()-1);
        
        return result;
    }
    
    public int findPathPeersNodeIdx(PeerNode peer) {
        int peerNodeIdx = -1;
        int loop = 0;
        PeerNode tempNode = null;
        
        while (loop < this.pathPeers.size()) {
            tempNode = (PeerNode) this.pathPeers.get(loop);
            
            if (tempNode.getNodeID().equals(peer.getNodeID())) {
                peerNodeIdx = loop;
                break;
            }
            
            loop++;
        }
        
        return peerNodeIdx;
    }
    
    public String getReqID() {
        return this.reqID;
    }
    
    public String getReqType() {
        return this.reqType;
    }
    
    public String getReqKeyword() {
        return this.reqKeyword;
    }
    
    public PeerNode getReqPeer() {
        return this.reqPeer;
    }
    
    public int getReqTtl() {
        return this.reqTtl;
    }
    
    public ArrayList<PeerNode> getPathPeers() {
        return this.pathPeers;
    }
    
    public Document toXMLDoc() throws Exception {
        Document doc;
        XMLTools xt = new XMLTools();        
        doc = xt.db.newDocument();
        
        Element rootEle = doc.createElement("Request");

        // ReqID
        Element reqIDEle = doc.createElement("Request:ID");
        Text reqIDText = doc.createTextNode(this.reqID);
        reqIDEle.appendChild(reqIDText);
        rootEle.appendChild(reqIDEle);  
        
        // ReqType
        Element reqTypeEle = doc.createElement("Request:Type");
        Text reqTypeText = doc.createTextNode(this.reqType);
        reqTypeEle.appendChild(reqTypeText);
        rootEle.appendChild(reqTypeEle);  
        
        // ReqKeyword
        Element reqKeywordEle = doc.createElement("Request:Keyword");
        Text reqKeywordText = doc.createTextNode(this.reqKeyword);
        reqKeywordEle.appendChild(reqKeywordText);
        rootEle.appendChild(reqKeywordEle); 
        
        // ReqPeer
        Element reqPeerEle = doc.createElement("Request:Peer");
            // ID
            Element peerNodeIDEle = doc.createElement("Request:Peer:ID");
            Text peerNodeIDText = doc.createTextNode(this.reqPeer.getNodeID());
            peerNodeIDEle.appendChild(peerNodeIDText);
            reqPeerEle.appendChild(peerNodeIDEle);        

            // IPaddress
            Element peerNodeIPaddressEle = doc.createElement("Request:Peer:IPaddress");
            Text peerNodeIPaddressText = doc.createTextNode(this.reqPeer.getNodeIPaddress());
            peerNodeIPaddressEle.appendChild(peerNodeIPaddressText);
            reqPeerEle.appendChild(peerNodeIPaddressEle);        

            // Port
            Element peerNodePortEle = doc.createElement("Request:Peer:Port");
            Text peerNodePortText = doc.createTextNode(Integer.toString(this.reqPeer.getNodePort()));
            peerNodePortEle.appendChild(peerNodePortText);
            reqPeerEle.appendChild(peerNodePortEle);
        
        rootEle.appendChild(reqPeerEle); 
        
        // ReqTTL
        Element reqTTLEle = doc.createElement("Request:TTL");
        Text reqTTLText = doc.createTextNode(Integer.toString(this.reqTtl));
        reqTTLEle.appendChild(reqTTLText);
        rootEle.appendChild(reqTTLEle); 
        
        // PathPeers
        Element pathPeersEle = doc.createElement("Request:Path");
        
            int pathPeersLoop = 0;
            PeerNode pathPeerNode = null;

            while (pathPeersLoop < this.pathPeers.size()) {
                Element pathPeerNodeEle = doc.createElement("Request:Path:Node");
                pathPeerNode = (PeerNode) this.pathPeers.get(pathPeersLoop);

                // ID
                Element pathPeerNodeIDEle = doc.createElement("Request:Path:Node:ID");
                Text pathPeerNodeIDText = doc.createTextNode(pathPeerNode.getNodeID());
                pathPeerNodeIDEle.appendChild(pathPeerNodeIDText);
                pathPeerNodeEle.appendChild(pathPeerNodeIDEle);        

                // IPaddress
                Element pathPeerNodeIPaddressEle = doc.createElement("Request:Path:Node:IPaddress");
                Text pathPeerNodeIPaddressText = doc.createTextNode(pathPeerNode.getNodeIPaddress());
                pathPeerNodeIPaddressEle.appendChild(pathPeerNodeIPaddressText);
                pathPeerNodeEle.appendChild(pathPeerNodeIPaddressEle);        

                // Port
                Element pathPeerNodePortEle = doc.createElement("Request:Path:Node:Port");
                Text pathPeerNodePortText = doc.createTextNode(Integer.toString(pathPeerNode.getNodePort()));
                pathPeerNodePortEle.appendChild(pathPeerNodePortText);
                pathPeerNodeEle.appendChild(pathPeerNodePortEle);        

                pathPeersEle.appendChild(pathPeerNodeEle);
                pathPeersLoop++;
            }
                        
        rootEle.appendChild(pathPeersEle); 
        
        doc.appendChild(rootEle);                
        
        return doc;
    }
    
    public String toXMLString() throws Exception {
        String result = null;
        
        XMLTools xt = new XMLTools();                
        result = xt.writeXMLString(this.toXMLDoc());
        
        return result;
    }
    
    public void toXMLFile(String fileName) throws Exception {
        // Prepare the DOM document for writing
        Source source = new DOMSource(this.toXMLDoc());

        // Prepare the output file
        File file = new File(fileName);
        Result result = new StreamResult(file);

        // Write the DOM document to the file
        Transformer xformer = TransformerFactory.newInstance().newTransformer();
        xformer.transform(source, result);
    }
    
    public Request fromXMLDoc(Document dom) {
        Request result = new Request();
        
        Element rootEle = dom.getDocumentElement();
        
        if (rootEle.getTagName().equals("Request")) {
            // ReqID
            NodeList reqIDList = rootEle.getElementsByTagName("Request:ID");
            String reqIDText = reqIDList.item(0).getFirstChild().getNodeValue();
            result.setReqID(reqIDText);
            
            // ReqType
            NodeList reqTypeList = rootEle.getElementsByTagName("Request:Type");
            String reqTypeText = reqTypeList.item(0).getFirstChild().getNodeValue();
            result.setReqType(reqTypeText);

            // ReqKeyword
            NodeList reqKeywordList = rootEle.getElementsByTagName("Request:Keyword");
            String reqKeywordText = reqKeywordList.item(0).getFirstChild().getNodeValue();
            result.setReqKeyword(reqKeywordText);

            // ReqPeer
            PeerNode reqPeerNode = new PeerNode();
            NodeList reqPeerNodeIDList = rootEle.getElementsByTagName("Request:Peer:ID");
            String reqPeerNodeIDText = reqPeerNodeIDList.item(0).getFirstChild().getNodeValue();
            NodeList reqPeerNodeIPaddressList = rootEle.getElementsByTagName("Request:Peer:IPaddress");
            String reqPeerNodeIPaddressText = reqPeerNodeIPaddressList.item(0).getFirstChild().getNodeValue();
            NodeList reqPeerNodePortList = rootEle.getElementsByTagName("Request:Peer:Port");
            String reqPeerNodePortText = reqPeerNodePortList.item(0).getFirstChild().getNodeValue();
            reqPeerNode.setNodeID(reqPeerNodeIDText);
            reqPeerNode.setNodeIPaddress(reqPeerNodeIPaddressText);
            reqPeerNode.setNodePort(Integer.valueOf(reqPeerNodePortText));
            result.setReqPeer(reqPeerNode);
            
            // ReqTTL
            NodeList reqTTLList = rootEle.getElementsByTagName("Request:TTL");
            String reqTTLText = reqTTLList.item(0).getFirstChild().getNodeValue();
            result.setReqTtl(Integer.valueOf(reqTTLText));
            
            // PathPeers
            NodeList pathPeersList = rootEle.getElementsByTagName("Request:Path");
            NodeList pathPeersNodeList = rootEle.getElementsByTagName("Request:Path:Node");

            int pathPeersLoop = 0;
            
            while (pathPeersLoop < pathPeersNodeList.getLength()) {
                NodeList pathPeersNodeListEle = pathPeersNodeList.item(pathPeersLoop).getChildNodes();
                
                PeerNode pathPeerNode = new PeerNode();
                
                String pathPeerNodeIDText = pathPeersNodeListEle.item(0).getFirstChild().getNodeValue();
                String pathPeerNodeIPaddressText = pathPeersNodeListEle.item(1).getFirstChild().getNodeValue();
                String pathPeerNodePortText = pathPeersNodeListEle.item(2).getFirstChild().getNodeValue();

                pathPeerNode.setNodeID(pathPeerNodeIDText);
                pathPeerNode.setNodeIPaddress(pathPeerNodeIPaddressText);
                pathPeerNode.setNodePort(Integer.valueOf(pathPeerNodePortText));

                result.pathPeers.add(pathPeerNode);
                
                pathPeersLoop++;
            }
            
        }
                
        return result;
    }
    
    public Request fromXMLString(String data) throws Exception {
        Document dom = null;
        XMLTools xt = new XMLTools();
        Request result = null;
        
        // Parse the XML stream input to Document type
        dom = xt.db.parse(new InputSource(new StringReader(data)));
        
        result = fromXMLDoc(dom);
        
        return result;
    }
    
    public Request fromXMLFile(String fileName) throws Exception {
        Document dom = null;
        File file = null;
        Request result = null;
        XMLTools xt = new XMLTools();
        
        // Parse the XML stream input to Document type
        file = new File(fileName);
        dom = xt.db.parse(file);
        
        result = fromXMLDoc(dom);
        
        return result;
    }    
    
//    public static void main(String[] args) throws Exception {
////        PeerNode p1 = new PeerNode("192.168.0.1", 9090);
////        PeerNode p2 = new PeerNode("192.168.0.2", 9090);
////        PeerNode p3 = new PeerNode("192.168.0.3", 9090);
////        PeerNode p4 = new PeerNode("192.168.0.4", 9090);
////        
////        Request req1 = new Request("file", "1.res", p1, 10, p2);
////        req1.addPathPeer(p3);
////        req1.addPathPeer(p4);
////        
////        req1.toXMLFile("./conf/req1.xml");
//        Request req1 = new Request();
//        req1 = req1.fromXMLFile("./conf/req1.xml");
//        
//        req1.toXMLFile("./conf/req2.xml");
//    }
}
